package org.kca.yarmour.view;

import static org.lwjgl.opengl.GL11.*;

import java.io.IOException;
import java.util.Arrays;

import org.kca.graphics.GameCore;
import org.kca.graphics.Texture;
import org.kca.graphics.TextureLoader;
import org.kca.yarmour.YAException;
import org.kca.yarmour.data.GlobalData.CargoType;
import org.kca.yarmour.data.GlobalData;
import org.kca.yarmour.data.Player;
import org.kca.yarmour.data.Town;
import org.kca.yarmour.utils.ImageUtils;
import org.kca.yarmour.utils.KcaGLUtils;

/**
 * This class implements a dialog for buying and selling items from the supermarket.
 * @author ctheng
 *
 */
public class TradeDialog extends PopupDialog
{
    private static final int DIALOG_WIDTH = 410;
    private static final int DIALOG_HEIGHT = 410;
    private static final int COL_HEADER_Y = 55;
    private static final int CARGO_Y = COL_HEADER_Y + 25;
    private static final int CARGO_Y_INTERVAL = 34;
    private static final int TEXT_Y_OFFSET = 6;
    private static final int ARROW_Y_OFFSET = 4;
    private static final int ARROW_SIZE = 24;
    private static final int CARGO_ICON_X = 8;
    private static final int PLAYER_QTY_X = 80;
    private static final int SUPPLY_QTY_X = PLAYER_QTY_X + 60;
    private static final int PRICE_X = SUPPLY_QTY_X + 70;
    private static final int L_ARROW_X = PRICE_X + 40;
    private static final int BUY_QTY_X = L_ARROW_X + 50 + ARROW_SIZE / 2;
    private static final int R_ARROW_X = BUY_QTY_X + 50 - ARROW_SIZE / 2;
    private static final int BUY_QTY_BOX_LX = L_ARROW_X + 30;
    private static final int BUY_QTY_BOX_RX = R_ARROW_X - 6;
    private static final int MAX_ARROW_X = R_ARROW_X + 30;
    private static final int REM_MONEY_Y = CARGO_Y + 5 + CARGO_Y_INTERVAL * CargoType.getNumTypes();
    private static final int USED_SPACE_Y = REM_MONEY_Y + 36;
    private static final int REM_QTY_X = CARGO_ICON_X + 100;
    private static final int OK_BUTTON_X = 340;
    private static final int OK_BUTTON_W = 60;
    private static final int BUTTON_H = 30;
    private static final int CLEAR_BUTTON_X = 270;
    private static final int CLEAR_BUTTON_W = 60;
    private static final int TAB_HEIGHT = 25;
    private static final int TAB_MID_WIDTH = 70;
    private static final int TAB_GRAD_WIDTH = 6;
    
    private int activeTab;
    private Town town;
    private Player player;
    private int[] buyQty;
    private Texture rightArrow, leftArrow, maxArrow, aseanIcon, cargoIcon;
    private int usedSpace, totalCost, numDialogCargo;
    private NumberDialog numDialog;
    private String closeNotification;
    
    public TradeDialog()
    {
        super (DIALOG_WIDTH, DIALOG_HEIGHT, "Supermarket");
        activeTab = 0;
        buyQty = new int[CargoType.getNumTypes()];
        TextureLoader loader = GameCore.getTextureLoader();
        closeNotification = "";
        try
        {
            rightArrow = loader.getTexture(GlobalData.RIGHT_ARROW_FILENAME);
            leftArrow = loader.getTexture(GlobalData.LEFT_ARROW_FILENAME);
            maxArrow = loader.getTexture(GlobalData.MAXIMUM_ARROW_FILENAME);
            aseanIcon = loader.getTexture(GlobalData.ASEAN_FILENAME);
            cargoIcon = loader.getTexture(GlobalData.CARGO_FILENAME);
        } 
        catch (IOException e)
        {
            throw new YAException(e);
        }
    }
    
    /**
     * Initializes the trade parameters for this dialog box. This consists of Town data
     * and Player data
     * @param town the town the player is trading in
     * @param player the player object
     */
    public void initTradeParameters(Town town, Player player)
    {
        this.town = town;
        this.player = player;
        Arrays.fill(buyQty, 0);
        usedSpace = 0;
        totalCost = 0;
        closeNotification = "";
    }
    
    @Override
    protected void drawContent()
    {
        // draw tab row
        KcaGLUtils.drawTabs(BORDER_WIDTH, TITLEBAR_HEIGHT, DIALOG_WIDTH - 2 * BORDER_WIDTH, 
                TAB_HEIGHT, TAB_MID_WIDTH, TAB_GRAD_WIDTH, 
                new String[] {"Buy", "Sell"}, DIALOG_FONT, activeTab);
        if (activeTab < 2)
        {
            // draw column headers
            glColor4f(0, 0, 0, 1);
            TITLEBAR_FONT.drawString("Cargo", CARGO_ICON_X - 3, COL_HEADER_Y);
            TITLEBAR_FONT.drawString("Qty", ImageUtils.centerAlignX(DIALOG_FONT, PLAYER_QTY_X, "Qty"), 
                    COL_HEADER_Y);
            TITLEBAR_FONT.drawString("Supply", ImageUtils.centerAlignX(DIALOG_FONT, SUPPLY_QTY_X, 
                    "Supply"), COL_HEADER_Y);
            TITLEBAR_FONT.drawString("Price", ImageUtils.centerAlignX(DIALOG_FONT, PRICE_X, "Price"), 
                    COL_HEADER_Y);
            String col4 = activeTab == 0 ? "Buy" : "Sell";
            TITLEBAR_FONT.drawString(col4, ImageUtils.centerAlignX(DIALOG_FONT, BUY_QTY_X, col4), 
                    COL_HEADER_Y);
            // draw goods and prices
            for (int i = 0; i < CargoType.getNumTypes(); i++)
            {
                KcaGLUtils.drawImage(CargoType.getCargoType(i).getImage(), CARGO_ICON_X, 
                        CARGO_Y + i * CARGO_Y_INTERVAL);
                glColor4f(0, 0, 0, 1);
                int arrowy = CARGO_Y + i * CARGO_Y_INTERVAL + ARROW_Y_OFFSET;
                KcaGLUtils.drawRect(BUY_QTY_BOX_LX, arrowy, BUY_QTY_BOX_RX - BUY_QTY_BOX_LX, ARROW_SIZE);
                int texty = CARGO_Y + i * CARGO_Y_INTERVAL + TEXT_Y_OFFSET;
                String pqty = String.valueOf(player.getCargo(i));
                String sqty = String.valueOf(town.getSupply(i));
                String priceStr = String.valueOf(activeTab == 0 ? 
                        town.getBuyPrice(i) : town.getSellPrice(i));
                String bqty = String.valueOf(buyQty[i]);
                DIALOG_FONT.drawString(pqty, ImageUtils.centerAlignX(DIALOG_FONT, PLAYER_QTY_X, pqty),
                        texty);
                DIALOG_FONT.drawString(sqty, ImageUtils.centerAlignX(DIALOG_FONT, SUPPLY_QTY_X, sqty),
                        texty);
                DIALOG_FONT.drawString(priceStr, ImageUtils.centerAlignX(DIALOG_FONT, PRICE_X, priceStr), 
                        texty);
                DIALOG_FONT.drawString(bqty, ImageUtils.centerAlignX(DIALOG_FONT, BUY_QTY_X, bqty), 
                        texty);
                
                KcaGLUtils.drawImage(leftArrow, L_ARROW_X, arrowy);
                KcaGLUtils.drawImage(rightArrow, R_ARROW_X, arrowy);
                KcaGLUtils.drawImage(maxArrow, MAX_ARROW_X, arrowy);
            }
            // draw total and summary
            KcaGLUtils.drawImage(aseanIcon, CARGO_ICON_X, REM_MONEY_Y);
            KcaGLUtils.drawImage(cargoIcon, CARGO_ICON_X, USED_SPACE_Y);
            glColor4f(0, 0, 0, 1);
            String rmStr = activeTab == 0 ? String.valueOf(player.getMoney() - totalCost) : 
                String.valueOf(player.getMoney() + totalCost);
            String usStr = activeTab == 0 ? String.valueOf(player.getCurrentCargo() + usedSpace) : 
                String.valueOf(player.getCurrentCargo() - usedSpace);
            TITLEBAR_FONT.drawString(rmStr, ImageUtils.rightAlignX(TITLEBAR_FONT, REM_QTY_X, rmStr),
                    REM_MONEY_Y + TEXT_Y_OFFSET);
            TITLEBAR_FONT.drawString(usStr, ImageUtils.rightAlignX(TITLEBAR_FONT, REM_QTY_X, usStr), 
                    USED_SPACE_Y + TEXT_Y_OFFSET);
            TITLEBAR_FONT.drawString("/ " + player.getMaxCargo(), REM_QTY_X + 5, 
                    USED_SPACE_Y + TEXT_Y_OFFSET);
            String tcStr = (activeTab == 0 ? "- " : "+ ") + (totalCost);
            if (totalCost == 0)
            {
                glColor4f(0, 0, 0, 1);
            }
            else if (activeTab == 0) // buy tab = red
            {
                glColor4f(1, 0, 0, 1);
            }
            else // sell tab = green
            {
                glColor4f(0, 1, 0, 1);
            }
            TITLEBAR_FONT.drawString(tcStr, ImageUtils.centerAlignX(TITLEBAR_FONT, BUY_QTY_X, tcStr),
                    REM_MONEY_Y + TEXT_Y_OFFSET);
            KcaGLUtils.drawButton(CLEAR_BUTTON_X, USED_SPACE_Y, CLEAR_BUTTON_W, BUTTON_H, 
                    TITLEBAR_FONT, "Clear", KcaGLUtils.BUTTON_ENABLED);
            KcaGLUtils.drawButton(OK_BUTTON_X, USED_SPACE_Y, OK_BUTTON_W, BUTTON_H, 
                    TITLEBAR_FONT, "Ok", KcaGLUtils.BUTTON_ENABLED);
            if (numDialog != null)
            {
                glColor4f(0, 0, 0, 0.5f);
                KcaGLUtils.fillRect(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT);
                numDialog.drawComponent(0, 0);
            }
        }
        else if (activeTab == 2)
        {
            // quest tab
        }
    }
    
    /**
     * Reduces the buying/selling quantity of a particular cargo type
     * @param cargo the cargo type
     */
    private void reduceQty(int cargo)
    {
        if (activeTab == 0)
        {
            if (buyQty[cargo] > 0)
            {
                buyQty[cargo]--;
                totalCost -= town.getBuyPrice(cargo);
                usedSpace--;
            }
        }
        else if (activeTab == 1)
        {
            if (buyQty[cargo] > 0)
            {
                buyQty[cargo]--;
                totalCost -= town.getSellPrice(cargo);
                usedSpace--;
            }
        }
    }
    
    /**
     * Increases the buying/selling quantity of a particular cargo type
     * @param cargo the cargo type
     */
    private void increaseQty(int cargo)
    {
        if (activeTab == 0)
        {
            if (player.getCurrentCargo() + usedSpace < player.getMaxCargo() && 
                    totalCost + town.getBuyPrice(cargo) < player.getMoney() &&
                    buyQty[cargo] < town.getSupply(cargo))
            {
                buyQty[cargo]++;
                totalCost += town.getBuyPrice(cargo);
                usedSpace++;
            }
        }
        else if (activeTab == 1)
        {
            if (buyQty[cargo] < player.getCargo(cargo))
            {
                buyQty[cargo]++;
                totalCost += town.getSellPrice(cargo);
                usedSpace++;
            }
        }
    }
    
    /**
     * Sets to the max quantity possible to buy or sell
     * @param cargo the cargo type
     */
    private void maximumQty(int cargo)
    {
        if (activeTab == 0)
        {
            int bq = (player.getMoney() - totalCost) / town.getBuyPrice(cargo);
            bq = Math.min(bq, town.getSupply(cargo) - buyQty[cargo]);
            bq = Math.min(bq, player.getMaxCargo() - player.getCurrentCargo() - usedSpace);
            buyQty[cargo] += bq;
            totalCost += bq * town.getBuyPrice(cargo);
            usedSpace += bq;
        }
        else if (activeTab == 1)
        {
            int diff = player.getCargo(cargo) - buyQty[cargo];
            buyQty[cargo] += diff;
            totalCost += diff * town.getSellPrice(cargo);
            usedSpace += diff;
        }
    }
    
    /**
     * Sets the buy/sell quantity for a particular cargo
     * @param cargo the cargo type
     * @param amount the amount to set
     */
    private void setQty(int cargo, int amount)
    {
        int diff = amount - buyQty[cargo];
        if (activeTab == 0)
        {
            buyQty[cargo] += diff;
            totalCost += diff * town.getBuyPrice(cargo);
            usedSpace += diff;
        }
        else if (activeTab == 1)
        {
            buyQty[cargo] += diff;
            totalCost += diff * town.getSellPrice(cargo);
            usedSpace += diff;
        }
    }
    
    /**
     * Opens a separate small dialog to enter the quantity
     * @param cargo the cargo type
     */
    private void openQtyDialog(int cargo)
    {
        if (activeTab > 1)
        {
            return;
        }
        String title = (activeTab == 0 ? "Buy " : "Sell ") + CargoType.getCargoName(cargo);
        int space = 0, cost = 0;
        for (int i = 0; i < CargoType.getNumTypes(); i++)
        {
            if (i == cargo)
            {
                continue;
            }
            space += buyQty[i];
            cost += buyQty[i] * town.getBuyPrice(i);
        }
        int bq = 0;
        if (activeTab == 0)
        {
            bq = (player.getMoney() - cost) / town.getBuyPrice(cargo);
            bq = Math.min(bq, town.getSupply(cargo));
            bq = Math.min(bq, player.getMaxCargo() - player.getCurrentCargo() - space);
        }
        else
        {
            bq = player.getCargo(cargo);
        }
        NumberDialog ndialog = new NumberDialog(title + " [0-" + bq + "]", buyQty[cargo], bq);
        ndialog.setX(100);
        ndialog.setY(100);
        ndialog.setDialogListener(this);
        ndialog.setMouseAccessProvider(this);
        numDialog = ndialog;
        numDialogCargo = cargo;
    }
    
    /**
     * Performs an action when OK is pressed
     */
    private void okPressed()
    {
        if (activeTab == 0)
        {
            int[] res = player.buyFromSupermarket(town, buyQty);
            int tc = 0;
            String cn = "Bought ";
            boolean flag = true;
            for (int i = 0; i < CargoType.getNumTypes(); i++)
            {
                tc += res[i] * town.getBuyPrice(i);
                if (res[i] != 0)
                {
                    if (!flag)
                    {
                        cn += ", ";
                    }
                    cn += res[i] + " " + CargoType.getCargoName(i);
                    flag = false;
                }
            }
            cn += " for " + tc + " Asean.";
            if (tc > 0)
            {
                closeNotification = cn;
            }
        }
        else if (activeTab == 1)
        {
            int[] res = player.sellToSupermarket(town, buyQty);
            int tc = 0;
            String cn = "Sold ";
            boolean flag = true;
            for (int i = 0; i < CargoType.getNumTypes(); i++)
            {
                tc += res[i] * town.getSellPrice(i);
                if (res[i] != 0)
                {
                    if (!flag)
                    {
                        cn += ", ";
                    }
                    cn += res[i] + " " + CargoType.getCargoName(i);
                    flag = false;
                }
            }
            cn += " for " + tc + " Asean.";
            if (tc > 0)
            {
                closeNotification = cn;
            }
        }
        if (getDialogListener() != null)
        {
            getDialogListener().actionPerformed(ACTION_OK_PRESSED);
        }
    }
    
    /**
     * Clears all the fields back to 0
     */
    private void clearPressed()
    {
        Arrays.fill(buyQty, 0);
        totalCost = 0;
        usedSpace = 0;
    }
    
    /**
     * Switches between buy and sell tabs
     * @param tab 0 for buy tab, 1 for sell tab
     */
    private void tabPressed(int tab)
    {
        if (activeTab == tab || tab < 0 || tab > 2)
        {
            return;
        }
        activeTab = tab;
        if (activeTab < 2)
        {
            Arrays.fill(buyQty, 0);
            totalCost = 0;
            usedSpace = 0;
        }
    }
    
    /**
     * Gets the notification to display when this dialog box is closed. This will be set if
     * the player buys or sells any items
     * @return the close notification
     */
    public String getCloseNotification()
    {
        return closeNotification;
    }
    
    @Override
    public void mousePressed(int button, int mx, int my)
    {
        if (numDialog != null)
        {
            numDialog.mousePressed(button, mx - numDialog.getX(), my - numDialog.getY());
            return;
        }
        boolean consumed = false;
        // Check for change of tab
        if (my >= TITLEBAR_HEIGHT && my < TITLEBAR_HEIGHT + TAB_HEIGHT)
        {
            for (int i = 0; i < 2; i++)
            {
                int xl = BORDER_WIDTH + (TAB_GRAD_WIDTH + TAB_MID_WIDTH) * i + TAB_GRAD_WIDTH;
                if (mx >= xl && mx < xl + TAB_MID_WIDTH)
                {
                    tabPressed(i);
                    return;
                }
            }
        }
        if (activeTab < 2)
        {
            /* Only if in buy or sell tabs */
            for (int i = 0; i < 7; i++)
            {
                int arrowy = CARGO_Y + i * CARGO_Y_INTERVAL + ARROW_Y_OFFSET;
                if (my >= arrowy && my < arrowy + ARROW_SIZE)
                {
                    if (mx >= L_ARROW_X && mx < L_ARROW_X + ARROW_SIZE)
                    {
                        reduceQty(i);
                        consumed = true;
                    }
                    else if (mx >= R_ARROW_X && mx < R_ARROW_X + ARROW_SIZE)
                    {
                        increaseQty(i);
                        consumed = true;
                    }
                    else if (mx >= MAX_ARROW_X && mx < MAX_ARROW_X + ARROW_SIZE)
                    {
                        maximumQty(i);
                        consumed = true;
                    }
                }
            }
            if (mx > OK_BUTTON_X && mx < OK_BUTTON_X + OK_BUTTON_W && 
                    my > USED_SPACE_Y && my < USED_SPACE_Y + BUTTON_H)
            {
                okPressed();
                consumed = true;
            }
            else if (mx > CLEAR_BUTTON_X && mx < CLEAR_BUTTON_X + CLEAR_BUTTON_W && 
                    my > USED_SPACE_Y && my < USED_SPACE_Y + BUTTON_H)
            {
                clearPressed();
                consumed = true;
            }
            else if (mx > BUY_QTY_BOX_LX && mx < BUY_QTY_BOX_RX)
            {
                for (int i = 0; i < CargoType.getNumTypes(); i++)
                {
                    int arrowy = CARGO_Y + i * CARGO_Y_INTERVAL + ARROW_Y_OFFSET;
                    if (my > arrowy && my < arrowy + ARROW_SIZE)
                    {
                        openQtyDialog(i);
                        consumed = true;
                    }
                }
            }
        }
        if (!consumed)
        {
            super.mousePressed(button, mx, my);
        }
    }
    
    @Override
    public void mouseReleased(int button, int mx, int my)
    {
        if (numDialog != null)
        {
            numDialog.mouseReleased(button, mx - numDialog.getX(), my - numDialog.getY());
            return;
        }
    }
    

    @Override
    public void keyPressed(int keyCode, int keyChar)
    {
        if (numDialog != null)
        {
            numDialog.keyPressed(keyCode, keyChar);
            return;
        }
    }

    @Override
    public void keyReleased(int keyCode, int keyChar)
    {
        if (numDialog != null)
        {
            numDialog.keyReleased(keyCode, keyChar);
            return;
        }
    }
    
    @Override
    public void actionPerformed(int action)
    {
        switch (action)
        {
        case ACTION_DIALOG_CLOSED:
            numDialog = null;
            break;
        case ACTION_OK_PRESSED:
            setQty(numDialogCargo, numDialog.getValue());
            numDialog = null;
            break;
        }
    }
}
